﻿using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using RockBus.BufferManager;
using RockBus.BufferManager.Interfaces;
using RockBus.CacheItemConfiguration;
using RockBus.CacheManager.Interfaces;
using RockBus.Composition.Interfaces;
using RockBus.Configuration;
using RockBus.Configuration.Interfaces;
using RockBus.ConfigurationService.Interfaces;
using RockBus.DataContracts;
using RockBus.Hosting;
using RockBus.Hosting.Interfaces;
using RockBus.Initialization;
using RockBus.Initialization.Interfaces;
using RockBus.Logging.Interfaces;
using RockBus.Logging.Log4Net;
using RockBus.MessageRepository.Db;
//using RockBus.MessageRepository.Dapper.Oracle.Db;
using RockBus.MessageRepository.Interfaces;
using RockBus.Messages;
using RockBus.Messages.Interfaces;
using RockBus.Monitoring;
using RockBus.Monitoring.Interfaces;
using RockBus.MonitoringService.Interfaces;
using RockBus.PerformanceCounters;
using RockBus.PerformanceCounters.Interfaces;
using RockBus.Pipeline;
using RockBus.Pipeline.Interfaces;
using RockBus.PipelineComponent.Xml;
using RockBus.Queueing.Interfaces;
using RockBus.Queueing.TplDataflow;
using RockBus.Routing;
using RockBus.Routing.Interfaces;
using RockBus.Routing.SendPorts;
using RockBus.Services;
using RockBus.Services.SignalR;
using RockBus.Services.WebApi;
using RockBus.Subscription.Evaluators;
using RockBus.Subscription.Interfaces;
using RockBus.SubscriptionRepository.Db;
//using RockBus.SubscriptionRepository.Dapper.Oracle.Db;
using RockBus.SubscriptionRepository.Interfaces;
using RockBus.Transport.Db;
using RockBus.Transport.Interfaces;
using RockBus.Transport.Wcf;
using System;
using System.Collections.Generic;
using System.Configuration;

namespace RockBus.Composition
{
    public abstract class UnityDependencyManager : IDependencyManager
    {
        protected UnityDependencyManager()
        {
            this._container = new Lazy<IUnityContainer>(this.CreateContainer, true);
        }

        private readonly Lazy<IUnityContainer> _container;

        private IUnityContainer Container
        {
            get { return this._container.Value; }
        }

        public T Resolve<T>()
        {
            return this.Container.Resolve<T>();
        }

        public T Resolve<T>(string name)
        {
            return this.Container.Resolve<T>(name);
        }

        public IEnumerable<T> ResolveAll<T>()
        {
            return this.Container.ResolveAll<T>();
        }

        public object Resolve(Type type)
        {
            return this.Container.Resolve(type);
        }

        public object Resolve(Type type, string name)
        {
            return this.Container.Resolve(type, name);
        }

        public IEnumerable<object> ResolveAll(Type type)
        {
            return this.Container.ResolveAll(type);
        }

        protected abstract IUnityContainer CreateContainer();
    }

    public abstract class DependencyManagerBase : UnityDependencyManager
    {
        protected DependencyManagerBase()
            : base()
        {
            // Trick to make sure we load the RockBus.PipelineComponents.Xml
            var plt = typeof(TransformationPipelineComponent);
        }

        protected override IUnityContainer CreateContainer()
        {
            var container = new UnityContainer();
            this.FillContainerWithCommonDependencies1(container);
            this.FillContainer(container);

            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Configure(container);

            this.FillContainerWithCommonDependencies2(container);
            this.FillContainerWithHostingDependencies(container);
            return container;
        }

        protected virtual void FillContainerWithCommonDependencies1(IUnityContainer container)
        {
            container

            // Configuration Dependencies
            .RegisterInstance<IInternalConfiguration>(ServiceBusConfigurationSection.Instance.InternalConfiguration, new ContainerControlledLifetimeManager())
            .RegisterType<IServiceBusExtensionsConfiguration, ServiceBusExtensionsConfiguration>(new ContainerControlledLifetimeManager())

            // Pervasive dependencies
            .RegisterType<ILogger, Log4NetLogger>(new ContainerControlledLifetimeManager())
            .RegisterType<IMessageFactory, MessageFactory>(new ContainerControlledLifetimeManager())

            // Initializations
            .RegisterType<IInitialization, ThreadPoolInitialization>(InstanceNames.ThreadPoolInitialization, new ContainerControlledLifetimeManager())
            .RegisterType<IInitialization, TaskSchedulerInitialization>(InstanceNames.TaskSchedulerInitialization, new ContainerControlledLifetimeManager())
            .RegisterType<IInitialization, CollectorManagerInitialization>(InstanceNames.CollectorManagerInitialization, new ContainerControlledLifetimeManager())
            .RegisterType<IInitializationManager, InitializationManager>(new ContainerControlledLifetimeManager())

            // Queue dependencies
            .RegisterType<IQueueFactory, QueueFactory>(new ContainerControlledLifetimeManager())
            .RegisterType<IQueueManager, QueueManager>(new ContainerControlledLifetimeManager())

            // PerformanceCounter dependencies
            .RegisterType<IPerformanceCounterConfiguration, PerformanceCounterConfiguration>(new ContainerControlledLifetimeManager())
            .RegisterType<IPerformanceCounterFactory, PerformanceCounterFactory>(new ContainerControlledLifetimeManager())
            .RegisterType<ICollectorManagerConfiguration, CollectorManagerConfiguration>(new ContainerControlledLifetimeManager())
            .RegisterType<ICollectorManager, CollectorManager>(new ContainerControlledLifetimeManager())

            // Pipeline dependencies
            .RegisterType<IPipelineFactory, PipelineFactory>(new ContainerControlledLifetimeManager())
            .RegisterType<IPipelineManager, PipelineManager>(new ContainerControlledLifetimeManager())

            .RegisterType<ICorrelationManager, CorrelationManager>(new ContainerControlledLifetimeManager())

            .RegisterType<IMessageProcessor, Routing.ReceivePort>(InstanceNames.ReceivePort, new ContainerControlledLifetimeManager())

            // SubscriptionManager dependencies
            .RegisterType<IMessageFilterFactory, MessageFilterFactory>(new ContainerControlledLifetimeManager())
            .RegisterType<IEvaluator<PublisherConfiguration>, ReceivePortEvaluator>(InstanceNames.ReceivePortEvaluator, new ContainerControlledLifetimeManager())
            .RegisterType<IEvaluator<SubscriberConfiguration>, TopicEvaluator>(InstanceNames.TopicEvaluator, new ContainerControlledLifetimeManager())
            .RegisterType<IEvaluator<SubscriberConfiguration>, SubscriptionEvaluator>(InstanceNames.SubscriptionEvaluator, new ContainerControlledLifetimeManager())
            .RegisterType<ISubscriptionManager, SubscriptionManager>(new ContainerControlledLifetimeManager())
            .RegisterType<ISubscriptionConfigurationManager, SubscriptionConfigurationManager>(new ContainerControlledLifetimeManager())
            .RegisterType<IMessageProcessor, EvaluationManager>(InstanceNames.EvaluationManager, new ContainerControlledLifetimeManager())

            // Transport dependencies
            .RegisterType<IServiceEndpointFactory, ServiceEndpointFactory>(new ContainerControlledLifetimeManager())
            .RegisterType<IServiceHostManager, SelfHostedServiceHostManager>(new ContainerControlledLifetimeManager())
            .RegisterType<ITransportFactory, TransportFactory>(InstanceNames.WcfTransportFactory, new ContainerControlledLifetimeManager())
            .RegisterType<ITransportManager, TransportManager>(new ContainerControlledLifetimeManager())
            ;
        }

        protected virtual void FillContainerWithCommonDependencies2(IUnityContainer container)
        {
            var receivePort = container.Resolve<IMessageProcessor>("ReceivePort") as IReceivePort;
            container.RegisterInstance<IReceivePort>(receivePort, new ContainerControlledLifetimeManager());

            container.RegisterType<RoutingManager>(new ContainerControlledLifetimeManager());
            var rm = container.Resolve<RoutingManager>();
        }

        protected virtual void FillContainerWithInMemorySubscriptionRespository(IUnityContainer container)
        {
            container
            .RegisterType<ICacheManager, RockBus.Caching.CacheManager>(new ContainerControlledLifetimeManager())
            .RegisterType<ICacheItemConfiguration, CacheItemConfiguration.CacheItemConfiguration>(InstanceNames.PersistencePublisherCacheItem, new ContainerControlledLifetimeManager(),
                new InjectionConstructor(InstanceNames.PersistencePublisherCacheItem))
            .RegisterType<ICacheItemConfiguration, CacheItemConfiguration.CacheItemConfiguration>(InstanceNames.PersistenceSubscriberCacheItem, new ContainerControlledLifetimeManager(),
                new InjectionConstructor(InstanceNames.PersistenceSubscriberCacheItem))
            .RegisterType<ISubscriptionRepository, RockBus.SubscriptionRepository.Cache.SubscriptionRepository>(new ContainerControlledLifetimeManager(),
                new InjectionConstructor(
                    new ResolvedParameter<ILogger>(),
                    new ResolvedParameter<ICacheManager>(),
                    new ResolvedParameter<ICacheItemConfiguration>(InstanceNames.PersistencePublisherCacheItem),
                    new ResolvedParameter<ICacheItemConfiguration>(InstanceNames.PersistenceSubscriberCacheItem)))
            ;
        }

        protected virtual void FillContainerWithSqlDbSubscriptionRespository(IUnityContainer container)
        {
            container
            .RegisterType<IDbSubscriptionRepositoryConfiguration, RockBus.SubscriptionRepository.Db.DbSubscriptionRepositoryConfiguration>(new ContainerControlledLifetimeManager())
          //.RegisterType<IDbSubscriptionRepositoryConfiguration, RockBus.SubscriptionRepository.Dapper.Db.DbSubscriptionRepositoryConfiguration>(new ContainerControlledLifetimeManager())
          //.RegisterType<IDbSubscriptionRepositoryConfiguration, RockBus.SubscriptionRepository.Dapper.Oracle.Db.DbSubscriptionRepositoryConfiguration>(new ContainerControlledLifetimeManager())
            .RegisterType<ISubscriptionRepository, RockBus.SubscriptionRepository.Db.SubscriptionRepository>(new ContainerControlledLifetimeManager())
          //.RegisterType<ISubscriptionRepository, RockBus.SubscriptionRepository.Dapper.Db.SubscriptionRepository>(new ContainerControlledLifetimeManager())
          //.RegisterType<ISubscriptionRepository, RockBus.SubscriptionRepository.Dapper.Oracle.Db.SubscriptionRepository>(new ContainerControlledLifetimeManager())
            ;
        }

        protected virtual void FillContainerWithSqlDbMessageRepository(IUnityContainer container)
        {
            container
            .RegisterType<IBufferManagerConfiguration, BufferManagerConfiguration>(new ContainerControlledLifetimeManager(),
                new InjectionConstructor(InstanceNames.DbMessageTransport))
            .RegisterType<IBufferManager, WcfBufferManager>(new ContainerControlledLifetimeManager())
            .RegisterType<IDbTransportConfiguration, DbTransportConfigurationImpl>(new ContainerControlledLifetimeManager())
            .RegisterType<IDbMessageRepositoryConfiguration, RockBus.MessageRepository.Db.DbMessageRepositoryConfiguration>(new ContainerControlledLifetimeManager())
          //.RegisterType<IDbMessageRepositoryConfiguration, RockBus.MessageRepository.Dapper.Db.DbMessageRepositoryConfiguration>(new ContainerControlledLifetimeManager())
          //.RegisterType<IDbMessageRepositoryConfiguration, RockBus.MessageRepository.Dapper.Oracle.Db.DbMessageRepositoryConfiguration>(new ContainerControlledLifetimeManager())
            .RegisterType<IMessageRepository, RockBus.MessageRepository.Db.MessageRepository>(new ContainerControlledLifetimeManager())
          //.RegisterType<IMessageRepository, RockBus.MessageRepository.Dapper.Db.MessageRepository>(new ContainerControlledLifetimeManager())
          //.RegisterType<IMessageRepository, RockBus.MessageRepository.Dapper.Oracle.Db.MessageRepository>(new ContainerControlledLifetimeManager())
            ;
        }

        protected virtual void FillContainerWithHostingDependencies(IUnityContainer container)
        {
            container
            .RegisterType<IReceivePortServiceHostFactory, SelfHostedServiceHostFactory<CbrService>>(new ContainerControlledLifetimeManager())
            .RegisterType<IServiceHostManager, SelfHostedServiceHostManager>(new ContainerControlledLifetimeManager())
            .RegisterType<IInitialization, ServiceHostManagerInitialization>(InstanceNames.ServiceHostManagerInitialization, new ContainerControlledLifetimeManager());
        }

        protected virtual void FillContainerWithWebApiDependencies(IUnityContainer container)
        {
            container

            // Services
            .RegisterType<IMonitoringService, Services.MonitoringService>(new ContainerControlledLifetimeManager())
            .RegisterType<IConfigurationService, Services.ConfigurationService>(new ContainerControlledLifetimeManager())

            // WebApi Controllers
            .RegisterType<MonitoringServiceController>()
            .RegisterType<ConfigurationServiceController>()

            // SignalR Hubs
            .RegisterType<MonitoringHub>()
            ;
        }

        protected abstract void FillContainer(IUnityContainer container);
    }
}